package net.mcfire.aliyunplugin;

import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.aliyun.log.producer.LogProducer;
import com.aliyun.openservices.aliyun.log.producer.Producer;
import com.aliyun.openservices.aliyun.log.producer.ProducerConfig;
import com.aliyun.openservices.aliyun.log.producer.ProjectConfig;
import com.aliyun.openservices.log.common.LogItem;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.ecs.model.v20140526.DescribeInstanceAttributeRequest;
import com.aliyuncs.ecs.model.v20140526.DescribeInstanceAttributeResponse;
import com.aliyuncs.profile.DefaultProfile;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.concurrent.*;
import java.util.logging.Logger;

public final class AliyunPlugin implements CommonPluginInterface {
    public static AliyunPlugin plugin = null;

    public static boolean bungee = false;

    public static String api_region_id;

    public static String ecs_region_id;
    public static String instance_id;

    public static RoomInfo roomInfo = null;

    public static String aliyunAccessKeyId = null;
    public static String aliyunAccessKeySecret = null;

    public static String aliyunLogEndpoint = null;
    public static String aliyunLogProject = null;
    public static String aliyunLogStore = null;
    public static Producer logProducer;

    public static String public_ip;

    private TopicLog topicAliyunPlugin;

    private final ConfigLoader configLoader;
    private final Logger logger;

    private ExecutorService executorService;

    public AliyunPlugin(ConfigLoader configLoader, Logger logger) {
        this.configLoader = configLoader;
        this.logger = logger;
    }

    @Override
    public Logger getLogger() {
        return logger;
    }

    @Override
    public void onLoad() {
        getLogger().info("Starting up thread pool... ");
        executorService = new ThreadPoolExecutor(1, 20, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());

        getLogger().info("Loading configuration... ");
        reloadConfig();

        reportIP();
    }

    @Override
    public void onEnable() {
        topicAliyunPlugin.info("Plugin enable");
    }

    private void reloadConfig() {
        getLogger().info("Reading server instance ID... ");
        try {
            BufferedReader reader = new BufferedReader(new FileReader("/opt/instance.txt"));
            instance_id = reader.readLine();
            reader.close();
        } catch (Exception ex) {
            ex.printStackTrace();
            getLogger().severe("Failed reading instance ID! ");
        }

        getLogger().info(String.format("Server Instance ID: %s", instance_id));

        getLogger().info("Reloading config... ");

        try {
            configLoader.reloadConfig();
        } catch (Exception ex) {
            ex.printStackTrace();
            getLogger().severe("FAILED LOADING CONFIGURATION! ");
            return;
        }

        // Get room info
        {
            JSONObject p = new JSONObject();
            p.put("i", instance_id);
            try {
                JSONObject jRoom = HTTP.api("/room/info", p).getJSONObject("data").getJSONObject("room");
                roomInfo = RoomInfo.from(jRoom);
            } catch (Exception ex) {
                ex.printStackTrace();
                getLogger().severe("FAILED LOADING ROOM INFO! ");
                return;
            }
        }

        getLogger().info(String.format("Aliyun API Region ID: %s", api_region_id));
        getLogger().info(String.format("ECS Instance Region ID: %s", ecs_region_id));
        getLogger().info(String.format("Aliyun RAM Info loaded, AccessKeyID=%s", aliyunAccessKeyId));
        getLogger().info(String.format("API Endpoint: %s", HTTP.api_endpoint));
        getLogger().info("Loading Aliyun logging service... ");
        ProducerConfig producerConfig = new ProducerConfig();
        logProducer = new LogProducer(producerConfig);
        logProducer.putProjectConfig(new ProjectConfig(aliyunLogProject, aliyunLogEndpoint, aliyunAccessKeyId, aliyunAccessKeySecret));
        getLogger().info("Aliyun logging service is online! ");

        topicAliyunPlugin = getTopicLog("AliyunPlugin");
    }

    private void reportIP() {
        if(!bungee) return;
        topicAliyunPlugin.info("Reporting IP... ");
        try {
            IAcsClient client = getAliyunClient();
            DescribeInstanceAttributeRequest req = new DescribeInstanceAttributeRequest();
            req.setSysRegionId(ecs_region_id);
            req.setInstanceId(instance_id);
            DescribeInstanceAttributeResponse response = client.getAcsResponse(req);
            public_ip = response.getPublicIpAddress().get(0);
            topicAliyunPlugin.debug(String.format("Public IP Address: %s", public_ip));
            JSONObject params = new JSONObject();
            params.put("i", instance_id);
            params.put("ip", public_ip);
            HTTP.api("/room/updateIP", params);
        } catch (Exception ex) {
            ex.printStackTrace();
            topicAliyunPlugin.error("Failed reporting IP! " + ex.getMessage());
        }
    }

    public ExecutorService getExecutorService() {
        return executorService;
    }

    public static void task(Runnable task) {
        plugin.executorService.execute(task);
    }

    public static Future<?> queueTask(Runnable task) {
        return plugin.executorService.submit(task);
    }

    public static TopicLog getTopicLog(String topic) { return new TopicLog(topic); }

    public static void sendLog(String topic, String level, LogItem item) {
        item.PushBack("level", level);
        try {
            logProducer.send(aliyunLogProject, aliyunLogStore, topic, instance_id, item);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static IAcsClient getAliyunClient() {
        DefaultProfile profile = DefaultProfile.getProfile(api_region_id, aliyunAccessKeyId, aliyunAccessKeySecret);
        return new DefaultAcsClient(profile);
    }
}
